package ru.galiauir.utils;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

import javax.naming.ConfigurationException;

public class PropertyFileReader {
	public static final String ALPHA = "imitator.alpha";
	public static final String MAX_DAYS = "imitator.max_days";
	public static final String INIT_USERS = "imitator.init_users";
	public static final String BETA = "imitator.beta";
	public static final String Y_RATIO = "imitator.y_ratio";
	public static final String AVERAGE_AMOUNT = "imitator.average_amnt";
	public static final String DISPERSIA = "imitator.dispersia";
	public static final String BASIC_COST = "imitator.basic_cost";
	
	private static PropertyFileReader instance;
	
	private Properties properties;
	
	private PropertyFileReader() {		
	}
	
	public synchronized static PropertyFileReader getInstance() {
		if (instance == null) {
			instance = new PropertyFileReader();
		}
		return instance;
	}
	
	public void readPropsFromFile(String fileName) throws FileNotFoundException, SecurityException, IOException, IllegalArgumentException { 
		properties = new Properties();
		properties.load(new FileInputStream(fileName));
	}
	
	private Object getProperty(String propertyName) throws ConfigurationException, NullPointerException {
		if (properties == null) {
			throw new NullPointerException();
		}
		Object prop = properties.get(propertyName);
		if (prop == null) {
			throw new ConfigurationException("No value for parameter " + propertyName);
		}
		return prop;
	}
	
	public <T> T getProperty(Class<T> clazz, String propertyName) throws NullPointerException, ConfigurationException, ClassCastException {
		Object prop = getProperty(propertyName);
		try {
			return clazz.cast(prop);
		} catch (ClassCastException e) {
			throw new ClassCastException("Invalid parameter value for " + propertyName);
		}
	}
	
	public int getIntProperty(String propertyName, Integer min, Integer max) throws NullPointerException, ConfigurationException, NumberFormatException {
		Object prop = getProperty(propertyName);
		try {
			Integer value;
			if (prop instanceof Integer) {
				value = (Integer) prop;
			} else {
				value = Integer.parseInt(prop.toString());
			}
			if (min != null && value.compareTo(min) < 0) {
				throw new ConfigurationException("Parameter value is less that allowed minimum of " + min.toString());
			}
			if (max != null && value.compareTo(max) > 0) {
				throw new ConfigurationException("Parameter value is greater that allowed maximum of " + max.toString());
			}
			return value;
		} catch (NumberFormatException e) {
			throw new NumberFormatException("Invalid parameter value for " + propertyName);
		}
	}
	
	public float getFloatProperty(String propertyName, Float min, Float max) throws NullPointerException, ConfigurationException, NumberFormatException {
		Object prop = getProperty(propertyName);
		try {
			Float value;
			if (prop instanceof Float) {
				value = (Float) prop;
			} else {
				value = Float.parseFloat(prop.toString());
			}
			if (min != null && value.compareTo(min) < 0) {
				throw new ConfigurationException("Parameter value is less that allowed minimum of " + min.toString());
			}
			if (max != null && value.compareTo(max) > 0) {
				throw new ConfigurationException("Parameter value is greater that allowed maximum of " + max.toString());
			}
			return value;
		} catch (NumberFormatException e) {
			throw new NumberFormatException("Invalid parameter value for " + propertyName);
		}
	}
	
	public long getLongProperty(String propertyName, Long min, Long max) throws NullPointerException, ConfigurationException, NumberFormatException {
		Object prop = getProperty(propertyName);
		try {
			Long value;
			if (prop instanceof Long) {
				value = (Long) prop;
			} else {
				value = Long.parseLong(prop.toString());
			}
			if (min != null && value.compareTo(min) < 0) {
				throw new ConfigurationException("Parameter value is less that allowed minimum of " + min.toString());
			}
			if (max != null && value.compareTo(max) > 0) {
				throw new ConfigurationException("Parameter value is greater that allowed maximum of " + max.toString());
			}
			return value;
		} catch (NumberFormatException e) {
			throw new NumberFormatException("Invalid parameter value for " + propertyName);
		}
	}
	
}
